package com.harvest.scientific.ladder.util

import android.app.Activity
import android.util.Log
import androidx.annotation.Nullable
import androidx.fragment.app.Fragment
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import java.lang.IllegalArgumentException
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.set

object FlowBus {
    private val busMap = ConcurrentHashMap<String, EventBus<*>>()
    private val busStickMap = ConcurrentHashMap<String, StickEventBus<*>>()

    @Synchronized
    fun <T> with(key: String): EventBus<T> {
        if (key.contains("_timestamp_")) {
            throw IllegalArgumentException("key can't contains '_timestamp_!'")
        }
        val key = "${key}_timestamp_${System.currentTimeMillis()}"
        var eventBus = busMap[key]
        if (eventBus == null) {
            eventBus = EventBus<T>(key)
            busMap[key] = eventBus
        }
        return eventBus as EventBus<T>
    }

    fun <T> post(key: String, value: T) {
        busMap.filter { it.key.split("_timestamp_")[0] == key }.forEach {
            (it.value as? EventBus<T>)?.send(value)
        }
    }

    open class EventBus<T>(private val key: String) : LifecycleObserver {

        protected val _events: MutableSharedFlow<T> by lazy {
            obtainEvent()
        }

        val events = _events.asSharedFlow()

        open fun obtainEvent(): MutableSharedFlow<T> =
            MutableSharedFlow(0, 1, BufferOverflow.DROP_OLDEST)

        private val observer by lazy {
            object : DefaultLifecycleObserver {

                override fun onPause(owner: LifecycleOwner) {
                    super.onPause(owner)
                    this@EventBus.onPause(owner)
                }

                override fun onDestroy(owner: LifecycleOwner) {
                    super.onDestroy(owner)
                    this@EventBus.onPause(owner)
                }

            }
        }

        protected open fun onPause(owner: LifecycleOwner) {
            when (owner) {
                is Activity -> {
                    if (owner.isFinishing) {
                        destroy()
                    }
                }
                is Fragment -> {

                    if (owner.isRemoving || owner.isDetached || owner?.parentFragment?.isRemoving == true) {
                        destroy()
                    } else {
                        runCatching { owner.requireActivity() }.getOrNull()?.let {
                            if (it.isFinishing) {
                                destroy()
                            }
                        }
                    }
                }

                else -> {
                    if (owner.javaClass.simpleName == "FragmentViewLifecycleOwner") {
                        runCatching {
                            owner.javaClass.getDeclaredField("mFragment")
                                .also { it.isAccessible = true }
                                .get(owner)
                                ?.let {it as? Fragment}
                                ?.let { fragment ->
                                    if (fragment.activity?.isFinishing == true) {
                                        destroy()
                                    }
                                }
                        }
                    }
                }
            }
        }

        protected var owner: LifecycleOwner? = null

        //主线程接收数据
        fun register(
            lifecycleOwner: LifecycleOwner,
            isDestroy: Boolean = false,
            action: (t: T) -> Unit,

            ) {
            owner = lifecycleOwner
            lifecycleOwner.lifecycle.addObserver(observer)
            lifecycleOwner.lifecycleScope.launch {
                launch {
                    events.collect {
                        try {
                            action(it)
                        } catch (e: Exception) {
                            LogUtils.e(TAG, "register e:${Log.getStackTraceString(e)}")
                        }
                    }
                }
                launch {
                    LogUtils.e(TAG, "register: isDestroy $isDestroy")
                    if (isDestroy) {
                        destroy()
                    }
                }
            }
        }

        fun send(event: T) {
            owner?.lifecycleScope?.launch {
                _events.emit(event)
            }
        }

        fun post(event: T) {
            runCatching {
                post(key.split("_timestamp_")[0], event)
                destroy()
            }.onFailure { LogUtils.e(TAG, "post error, ${Log.getStackTraceString(it)}") }
        }

        fun post(scope: CoroutineScope, event: T) {
            scope.launch {
                _events.emit(event)
            }
        }

        fun post(lifecycleOwner: LifecycleOwner, event: T) {

            lifecycleOwner.lifecycle.addObserver(observer)
            lifecycleOwner.lifecycleScope.launch {
                _events.emit(event)
            }
        }

        fun destroy() {

            val subscriptCount = _events.subscriptionCount.value
            if (busStickMap.containsKey(key)) {
                busStickMap.remove(key)
            } else if (busMap.containsKey(key)) {
                busMap.remove(key)
            }
            owner = null
            LogUtils.e(
                TAG,
                "onDestroy: FlowBus - onDestroy $subscriptCount $key \n:${busMap.keys}",
            )
        }

    }

    class StickEventBus<T>(val key: String, private val autoUnregister: Boolean = true) :
        EventBus<T>(key) {
        override fun obtainEvent(): MutableSharedFlow<T> =
            MutableSharedFlow(1, 1, BufferOverflow.DROP_OLDEST)


        override fun onPause(owner: LifecycleOwner) {
            if (autoUnregister) {
                super.onPause(owner)
            }
        }
    }


    const val TAG = "Bus"

}

class FlowBusConstant {

    companion object {

        const val REFRESH_HOME: String = "refresh_home"
        const val UPDATE_LOCALE = "update_locale"

        const val GO_HOME = "go_home"

        const val CLOSE_INFO = "close_info"

        const val KILL_SETTING_PAGE = "kill_setting_page"
    }
}
